from mydb.postgre import base

from os import path
from datetime import datetime, timedelta
from codecs import open

__dir__ = path.dirname(path.abspath(__file__))
log_path_refs = path.join(__dir__, "refs.log")
log_path_vals = path.join(__dir__, "vals.log")
log_path = path.join(__dir__, "tables.log")
log_path_links = path.join(__dir__, "links.log")

base=base()

base.user='buh'
base.passwd='joczkRX7MkJrPk'
base.host='sa-serv10'
base.port=5432
base.base='ZUP_TEK'

def values(sums=[], table_mask="LIKE '%%'", fields=None):
	"This function returns list of table-field pairs from fields list contain all the given sums"
	log_file = open(log_path_vals, 'a', 'utf-8')
	log_file.write('\n\n'+str(datetime.now())+'     Starting function: values\nWith arguments:\nSums: '+', '.join(sums)+'\nMask: '+table_mask+'\n')
	#Если список сумм непустой:
	if sums:
		#Устнавливается флаг отключения
		conn_flag=False
		#Если подключение к базе данных отсутствует
		if not base.conn:
			#Создается подключение
			base.connect()
			#Устанавливается флаг отключения
			conn_flag=True
		#Если функция не получила аргумента fields
		if fields==None:
			#Выбирается список полей таблиц схемы public
			fields=base.conn.prepare("SELECT table_name, column_name FROM information_schema.columns WHERE table_schema='public' AND column_name NOT LIKE '%_lineno%'AND table_name "+table_mask)()
		result=[]
		#Для каждого поля в таблице:
		for field in fields:
			#Устанавливается флаг включения поля в результат=True
			flag=True
			#Подготавливается запрос на выборку из поля field[1] таблицы field[0] записей с соответствующим значением поля field[1]
			select=base.conn.prepare("SELECT "+field[1]+" FROM "+field[0]+" WHERE "+field[1]+"=$1")
			#Для каждой суммы
			for sum in sums:
				#Проверяется:
				try:
					#Возможность выборки данной суммы из поля field[1] таблицы field[0]
					records=select(sum)
				#Если невозможно (например не соответствует тип данных)
				except:
					# То flag включения в результат = False
					flag=False
				#Если возможно
				else:
					if not records:
						#то флаг=False
						flag=False
			#Если все sums есть в этом поле
			if flag:
				#К результирующему списку прибавляется список: [таблица, поле]
				result+=[[field[0], field[1], sums]]
				# Для немедленного ознакомления список выводится на экран
				print([field[0], field[1]])
		#Logging
		if result:
			log_file.write('Все суммы найдены в следующих таблицах:\n')
			for item in result:
				log_file.write(item[0]+'('+item[1]+')\n')
		else:
			log_file.write('Все суммы не найдены ни в одной таблице\n')
		#Если флаг отключения True
		if conn_flag:
			#Закрывается подключение к базе данных
			base.disconnect()
	else:
		result=None
		log_file.write('Function got no arguments')
	log_file.write(str(datetime.now())+'     Finish function: values')
	log_file.close()
	#end of function suite
	#Функция возвращает список результатов
	return result

def refs(words=[], table_mask="LIKE '%%'", fields=None):
	"This function returns list of table-idreff pairs from fields list for all the given words"
	log_file = open(log_path_refs, 'a', 'utf-8')
	log_file.write('\n\n'+str(datetime.now())+'     Starting function: refs\nWith arguments:\nWords: '+', '.join(words)+'\nMask: '+table_mask+'\n')
	if words:
		#Устнавливается флаг отключения
		conn_flag=False
		#Если подключение к базе данных отсутствует
		if not base.conn:
			#Создается подключение
			base.connect()
			#Устанавливается флаг отключения
			conn_flag=True
		#Если функция не получила аргумента fields
		if fields==None:
			#Выбирается список полей таблиц схемы public
			fields=base.conn.prepare("SELECT table_name, column_name FROM information_schema.columns WHERE table_schema='public' AND table_name "+table_mask)()
		result=[]
		logwords=[]
		#Для каждого поля в таблице:
		for field in fields:
			#Проверяется:
			try:
				#Возможность запроса на выборку из поля _idrref таблицы field[0]
				select=base.conn.prepare("SELECT _idrref FROM "+field[0])
			#Если невозможно (например не соответствует тип данных)
			except:
				#То ничего
				pass
			#Если возможно
			else:
				#Для каждого слова в списке:
				for word in words:
					#Проверяется:
					try:
						#Возможность выборки idreff для записей с соответствующим словом в поле field[1]
						records=base.conn.prepare("SELECT _idrref, "+field[1]+" FROM "+field[0]+" WHERE "+field[1]+" LIKE "+word)
					#Если невозможно (например не соответствует тип данных)
					except:
						#То ничего
						pass
					#Если возможно
					else:
						if records() and word not in logwords: logwords+=[word]
						#Для каждой записи:
						for record in records:
							#Если данной записи еще нет в результирующем списке:
							if [field[0], record[0], record[1], word] not in result:
								#К результирующему списку прибавляется список: [таблица, idreff, слово]
								result+=[[field[0], record[0], record[1], word]]
								# Для немедленного ознакомления список выводится на экран
								print([field[0], record[1]])
		#Logging
		for logword in logwords:
			log_file.write('Для слова: '+logword+' найдено поле _idreff в таблицах: \n')
			for item in result:
				if item[3]==logword:
					log_file.write(item[0]+' ('+str(item[2])+')\n')
					
		#Если флаг отключения True
		if conn_flag:
			#Закрывается подключение к базе данных
			base.disconnect()
		#end of function suite
	#Иначе
	else:
		log_file.write('Function got no arguments')
		result=[]
	log_file.write(str(datetime.now())+'     Finish function: refs')
	log_file.close()
	#end of function suite
	#Функция возвращает список результатов
	return result

def tables(sums, words, words_mask):
	"This function returns list of table-field-corrtable for the given words and sums"
	#beginnig of function suite
	log_file = open(log_path, 'a', 'utf-8')
	log_file.write('\n\n'+str(datetime.now())+'     Starting function: tables\nWith arguments:\nSums: '+', '.join(sums)+'\nWords: '+', '.join(words)+'\nMask: '+words_mask+'\n')
	if words and sums:
		#Создается подключение к базе данных
		base.connect()
		#Создается пустой словарь результатов
		result={}
		#Выбирается список полей таблиц схемы public
		fields=base.conn.prepare("SELECT table_name, column_name FROM information_schema.columns WHERE table_schema='public'")()
		#Создается список таблиц, содержащих суммы sums
		tables=values(sums, "LIKE '%%'", fields)
		#Создается список таблиц, содержащих idreff для words
		idreffs=refs(words, words_mask, fields)
		#Для каждой таблицы в tables:
		for table in tables:
			#В словарь результатов добавляется запись для сумм
			log_file.write('\nТаблица: '+table[0]+'\n')
			log_file.write('Суммы: ('+table[1]+')\nСлова:\n')
			result[table[0]]=[[table[2], table[1], table[0]]]
			#Создается список полей таблицы
			table_fields=base.conn.prepare("SELECT column_name FROM information_schema.columns WHERE table_schema='public' and table_name=$1")(table[0])
			#Для каждого поля в table_fields:
			for table_field in table_fields:
				#Подготавливается запрос на выборку значения из данного поля данной таблицы
				select=base.conn.prepare("SELECT "+table_field[0]+" FROM "+table[0]+" WHERE "+table_field[0]+"=$1")
				#Для каждого idreff в idreffs
				for idreff in idreffs:
					#Проверяется:
					try:
						#Возможность выборки данного idreff из данного поля данной таблицы
						records=select(idreff[1])
					#Если невозможно (например не соответствует тип данных)
					except:
						#То ничего
						pass
					#Если возможно
					else:
						#То если запрос возвращает непустой результат:
						if records and [idreff[2], table_field[0], idreff[0]] not in result[table[0]]:
							#В словарь результатов для данной таблицы в список значение-поле-таблица добавляются элементы
							result[table[0]]+=[[idreff[2], table_field[0], idreff[0]]]
							# Для немедленного ознакомления список выводится на экран
							print([table[0], idreff[2], table_field[0], idreff[0]])
							log_file.write('('+idreff[2]+' : '+table_field[0]+' : '+idreff[0]+')\n')
		#Закрывается подключение к базе данных
		base.disconnect()
	#Иначе
	else:
		log_file.write('Function got no arguments')
		result=None
	log_file.write(str(datetime.now())+'     Finish function: tables')
	log_file.close()
	#end of function suite
	#Функция возвращает словарь результатов
	return result


def links(table, full=False, search_mask="LIKE '%%'"):
	"This function returns list of table-поле типа bytea pairs for bytea fields of the table"
	table=table.lower()
	log_file = open(log_path_links, 'a', 'utf-8')
	log_file.write('\n\n'+str(datetime.now())+'     Starting function: links\nWith arguments:\nTable: '+table+'\nSeacrh mask: '+search_mask+'\n')
	#Создается подключение
	base.connect()
	#Выбирается список полей таблиц схемы public
	if full:
		fields=base.conn.prepare("SELECT table_name, column_name FROM information_schema.columns WHERE table_schema='public' AND data_type='bytea' AND table_name "+search_mask+" AND table_name != "+"'"+table+"'")()
	else:
		fields=base.conn.prepare("SELECT table_name, column_name FROM information_schema.columns WHERE table_schema='public' AND column_name='_idrref' AND table_name "+search_mask+" AND table_name != "+"'"+table+"'")()
	table_fields=base.conn.prepare("SELECT column_name FROM information_schema.columns WHERE table_schema='public' AND data_type='bytea' AND table_name = "+"'"+table+"'")()
	result={}
	#Для каждого поля в таблице:
	for table_field in table_fields:
		count=0
		starttime=datetime.now()
		print('start time for the field '+table_field[0]+': '+str(starttime))
		print(table_field[0])
		result[table_field[0]]=[]
		for field in fields:
			count+=1
			
			if count in range(1000, 20000, 1000):
				print(str(count) + ' columns checked for the field '+table_field[0])
			
			#print([count, "SELECT COUNT(a."+field[1]+") FROM "+field[0]+" a, "+table+" b WHERE a."+field[1]+"=b."+table_field[0]])
			
			#Подсчитывается количество в поле field[1] таблицы field[0] значений поля table_field[0] таблицы
			records=base.conn.prepare("SELECT COUNT(a."+field[1]+") FROM "+field[0]+" a, "+table+" b WHERE a."+field[1]+"=b."+table_field[0])()
			#Если результат запроса больше нуля:
			if records[0][0]>0:
				#Тогда в словарь результатов для данного поля добавляется таблица
				result[table_field[0]]+=[[field[0],field[1]]]
				#Для немедленного отображения:
				print([count, table_field[0], field[0], field[1]])
		print('minutes spent for the field '+table_field[0]+': '+str(((datetime.now()-starttime).seconds)/60))
	#Logging
	for item in result:
		if result[item]:
			log_file.write('Для поля: '+item+' найдены поля типа bytea в таблицах: \n')
			for table in result[item]:
				log_file.write('     ('+table[0]+','+table[1]+')'+'\n')
		else:
			log_file.write('Для поля: '+item+' не найдены поля типа bytea ни в одной таблице!\n')
	log_file.write(str(datetime.now())+'     Finish function: links')
	#Закрывается подключение к базе данных
	base.disconnect()
	#end of function suite
	#Функция возвращает словарь результатов
	return result